package gui.event;

import core.Physics;
import gui.GameConstants;
import gui.MainWindow;
import gui.PlayersMap;
import gui.ToolContainer;
import gui.drawers.BallDrawer;

import dal.object.Card;
import dal.object.MapObject;
import dal.object.grounds.Water;

public class GameController {
	private static Sink sink;
	private static Card previous;
	private static PlayersMap pm;
	private static boolean sinking;
	private static int numberOfCards;
	private static ToolContainer tools;
	private static BallDrawer bd;
	
	public GameController(PlayersMap player, ToolContainer tc){
		pm = player;
		bd = (BallDrawer) pm.getJLayeredPane().getComponentsInLayer(GameConstants.BALL_LAYER)[0];
		sink = new Sink(bd);
		sinking = false;
		tools = tc;
	}
	
	/**
	 * @param mo
	 * 	if mo is a Water type MapObject, the ball begin to sink
	 */
	public static void sinking(MapObject mo) {
		if(mo instanceof Water){
			if(!sinking){
				sink.start();
				sinking = true;
			}
		} else if(sinking) {
			sink.stop();
			sinking = false;
		}
	}
	
	/**
	 * @param cards
	 * 	the number of cards in a map
	 */
	public static void setCards(int cards){
		numberOfCards = cards;
	}

	/**
	 * @param current
	 * 	the touched card
	 * 	if the previous card was the same type then the number of cards will decrease with 2
	 * 	otherwise the previous card will close
	 */
	public static void setCard(Card current) {
		if(previous != null){
			if(previous.getClass().isAssignableFrom(current.getClass())){
				previous.finalizeCard();
				current.finalizeCard();
				previous = null;
				
				numberOfCards -= 2;
				
				if(numberOfCards <= 0){
					gameComplete();
				}
			} else {
				previous.setVisible(false);
				previous = current;
			}
		} else {
			previous = current;
		}
	}

	/**
	 * The game over and the panel will be replaced with the game over menu
	 */
	public static void gameOver() {
		if(tools.hasLives()){
			pm.restart();
			bd.restart();
			Physics.setVelocity(0, 0);
		} else {
			PlayersMap.getPhysics().stopTime();
			MainWindow.getMainWindow().switchGameOver();
		}
	}
	
	/**
	 * it is the as game over but it happens when all cards showing
	 */
	public static void gameComplete() {
		PlayersMap.getPhysics().stopTime();
		sink.stop();
		MainWindow.getMainWindow().switchGameOver();
	}

	/**
	 * stops the game along with physics and sinking
	 */
	public static void stop() {
		Physics ps = PlayersMap.getPhysics();

		if(ps != null){
			ps.stopTime();
			sink.stop();
		}
	}
}

/**
 * @author nosxp
 *	Controlls the sinking of the ball in the water
 */
class Sink implements Runnable {
	private Thread play;
	private long time = 100;
	private BallDrawer bd;
	
	public Sink(BallDrawer bd) {
		this.bd = bd;
	}

	/**
	 * starts the thread
	 */
	public void start(){
		if(play == null){
			play = new Thread(this);
			play.start();
			bd.initSinking();
		}
	}
	
	/**
	 * stops the thread
	 */
	public void stop(){
		bd.resetBall();
		play = null;
	}
	
	public void run() {			
		while(play != null && bd.sinkingBall()) {
			sleep();
		}
		
		if(play != null){
			GameController.gameOver();
			play = null;
		}
	}	
	
	private void sleep(){
		try{
			Thread.sleep(time);
		} catch(InterruptedException ie) {
			System.out.println("interrupted sink");
		}
	}
}